home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclNotify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  22.2 KB  |  858 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclNotify.c --
  3.  *
  4.  *    This file implements the generic portion of the Tcl notifier.
  5.  *    The notifier is lowest-level part of the event system.  It
  6.  *    manages an event queue that holds Tcl_Event structures.  The
  7.  *    platform specific portion of the notifier is defined in the
  8.  *    tcl*Notify.c files in each platform directory.
  9.  *
  10.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) tclNotify.c 1.15 97/06/18 17:14:04
  16.  */
  17.  
  18. #include "tclInt.h"
  19. #include "tclPort.h"
  20.  
  21. /*
  22.  * The following static indicates whether this module has been initialized.
  23.  */
  24.  
  25. static int initialized = 0;
  26.  
  27. /*
  28.  * For each event source (created with Tcl_CreateEventSource) there
  29.  * is a structure of the following type:
  30.  */
  31.  
  32. typedef struct EventSource {
  33.     Tcl_EventSetupProc *setupProc;
  34.     Tcl_EventCheckProc *checkProc;
  35.     ClientData clientData;
  36.     struct EventSource *nextPtr;
  37. } EventSource;
  38.  
  39. /*
  40.  * The following structure keeps track of the state of the notifier.
  41.  * The first three elements keep track of the event queue.  In addition to
  42.  * the first (next to be serviced) and last events in the queue, we keep
  43.  * track of a "marker" event.  This provides a simple priority mechanism
  44.  * whereby events can be inserted at the front of the queue but behind all
  45.  * other high-priority events already in the queue (this is used for things
  46.  * like a sequence of Enter and Leave events generated during a grab in
  47.  * Tk).
  48.  */
  49.  
  50. static struct {
  51.     Tcl_Event *firstEventPtr;    /* First pending event, or NULL if none. */
  52.     Tcl_Event *lastEventPtr;    /* Last pending event, or NULL if none. */
  53.     Tcl_Event *markerEventPtr;    /* Last high-priority event in queue, or
  54.                  * NULL if none. */
  55.     int serviceMode;        /* One of TCL_SERVICE_NONE or
  56.                  * TCL_SERVICE_ALL. */
  57.     int blockTimeSet;        /* 0 means there is no maximum block
  58.                  * time:  block forever. */
  59.     Tcl_Time blockTime;        /* If blockTimeSet is 1, gives the
  60.                  * maximum elapsed time for the next block. */
  61.     int inTraversal;        /* 1 if Tcl_SetMaxBlockTime is being
  62.                  * called during an event source traversal. */
  63.     EventSource *firstEventSourcePtr;
  64.                 /* Pointer to first event source in
  65.                  * global list of event sources. */
  66. } notifier;
  67.  
  68. /*
  69.  * Declarations for functions used in this file.
  70.  */
  71.  
  72. static void    InitNotifier _ANSI_ARGS_((void));
  73. static void    NotifierExitHandler _ANSI_ARGS_((ClientData clientData));
  74.  
  75.  
  76. /*
  77.  *----------------------------------------------------------------------
  78.  *
  79.  * InitNotifier --
  80.  *
  81.  *    This routine is called to initialize the notifier module.
  82.  *
  83.  * Results:
  84.  *    None.
  85.  *
  86.  * Side effects:
  87.  *    Creates an exit handler and initializes static data.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91.  
  92. static void
  93. InitNotifier()
  94. {
  95.     initialized = 1;
  96.     memset(¬ifier, 0, sizeof(notifier));
  97.     notifier.serviceMode = TCL_SERVICE_NONE;
  98.     Tcl_CreateExitHandler(NotifierExitHandler, NULL);
  99. }
  100.  
  101. /*
  102.  *----------------------------------------------------------------------
  103.  *
  104.  * NotifierExitHandler --
  105.  *
  106.  *    This routine is called during Tcl finalization.
  107.  *
  108.  * Results:
  109.  *    None.
  110.  *
  111.  * Side effects:
  112.  *    Clears the notifier intialization flag.
  113.  *
  114.  *----------------------------------------------------------------------
  115.  */
  116.  
  117. static void
  118. NotifierExitHandler(clientData)
  119.     ClientData clientData;  /* Not used. */
  120. {
  121.     initialized = 0;
  122. }
  123.  
  124. /*
  125.  *----------------------------------------------------------------------
  126.  *
  127.  * Tcl_CreateEventSource --
  128.  *
  129.  *    This procedure is invoked to create a new source of events.
  130.  *    The source is identified by a procedure that gets invoked
  131.  *    during Tcl_DoOneEvent to check for events on that source
  132.  *    and queue them.
  133.  *
  134.  *
  135.  * Results:
  136.  *    None.
  137.  *
  138.  * Side effects:
  139.  *    SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent
  140.  *    runs out of things to do.  SetupProc will be invoked before
  141.  *    Tcl_DoOneEvent calls select or whatever else it uses to wait
  142.  *    for events.  SetupProc typically calls functions like Tcl_WatchFile
  143.  *    or Tcl_SetMaxBlockTime to indicate what to wait for.
  144.  *
  145.  *    CheckProc is called after select or whatever operation was actually
  146.  *    used to wait.  It figures out whether anything interesting actually
  147.  *    happened (e.g. by calling Tcl_FileReady), and then calls
  148.  *    Tcl_QueueEvent to queue any events that are ready.
  149.  *
  150.  *    Each of these procedures is passed two arguments, e.g.
  151.  *        (*checkProc)(ClientData clientData, int flags));
  152.  *    ClientData is the same as the clientData argument here, and flags
  153.  *    is a combination of things like TCL_FILE_EVENTS that indicates
  154.  *    what events are of interest:  setupProc and checkProc use flags
  155.  *    to figure out whether their events are relevant or not.
  156.  *
  157.  *----------------------------------------------------------------------
  158.  */
  159.  
  160. void
  161. Tcl_CreateEventSource(setupProc, checkProc, clientData)
  162.     Tcl_EventSetupProc *setupProc;    /* Procedure to invoke to figure out
  163.                      * what to wait for. */
  164.     Tcl_EventCheckProc *checkProc;    /* Procedure to call after waiting
  165.                      * to see what happened. */
  166.     ClientData clientData;        /* One-word argument to pass to
  167.                      * setupProc and checkProc. */
  168. {
  169.     EventSource *sourcePtr;
  170.  
  171.     if (!initialized) {
  172.     InitNotifier();
  173.     }
  174.  
  175.     sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
  176.     sourcePtr->setupProc = setupProc;
  177.     sourcePtr->checkProc = checkProc;
  178.     sourcePtr->clientData = clientData;
  179.     sourcePtr->nextPtr = notifier.firstEventSourcePtr;
  180.     notifier.firstEventSourcePtr = sourcePtr;
  181. }
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * Tcl_DeleteEventSource --
  187.  *
  188.  *    This procedure is invoked to delete the source of events
  189.  *    given by proc and clientData.
  190.  *
  191.  * Results:
  192.  *    None.
  193.  *
  194.  * Side effects:
  195.  *    The given event source is cancelled, so its procedure will
  196.  *    never again be called.  If no such source exists, nothing
  197.  *    happens.
  198.  *
  199.  *----------------------------------------------------------------------
  200.  */
  201.  
  202. void
  203. Tcl_DeleteEventSource(setupProc, checkProc, clientData)
  204.     Tcl_EventSetupProc *setupProc;    /* Procedure to invoke to figure out
  205.                      * what to wait for. */
  206.     Tcl_EventCheckProc *checkProc;    /* Procedure to call after waiting
  207.                      * to see what happened. */
  208.     ClientData clientData;        /* One-word argument to pass to
  209.                      * setupProc and checkProc. */
  210. {
  211.     EventSource *sourcePtr, *prevPtr;
  212.  
  213.     for (sourcePtr = notifier.firstEventSourcePtr, prevPtr = NULL;
  214.         sourcePtr != NULL;
  215.         prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {
  216.     if ((sourcePtr->setupProc != setupProc)
  217.         || (sourcePtr->checkProc != checkProc)
  218.         || (sourcePtr->clientData != clientData)) {
  219.         continue;
  220.     }
  221.     if (prevPtr == NULL) {
  222.         notifier.firstEventSourcePtr = sourcePtr->nextPtr;
  223.     } else {
  224.         prevPtr->nextPtr = sourcePtr->nextPtr;
  225.     }
  226.     ckfree((char *) sourcePtr);
  227.     return;
  228.     }
  229. }
  230.  
  231. /*
  232.  *----------------------------------------------------------------------
  233.  *
  234.  * Tcl_QueueEvent --
  235.  *
  236.  *    Insert an event into the Tk event queue at one of three
  237.  *    positions: the head, the tail, or before a floating marker.
  238.  *    Events inserted before the marker will be processed in
  239.  *    first-in-first-out order, but before any events inserted at
  240.  *    the tail of the queue.  Events inserted at the head of the
  241.  *    queue will be processed in last-in-first-out order.
  242.  *
  243.  * Results:
  244.  *    None.
  245.  *
  246.  * Side effects:
  247.  *    None.
  248.  *
  249.  *----------------------------------------------------------------------
  250.  */
  251.  
  252. void
  253. Tcl_QueueEvent(evPtr, position)
  254.     Tcl_Event* evPtr;        /* Event to add to queue.  The storage
  255.                  * space must have been allocated the caller
  256.                  * with malloc (ckalloc), and it becomes
  257.                  * the property of the event queue.  It
  258.                  * will be freed after the event has been
  259.                  * handled. */
  260.     Tcl_QueuePosition position;    /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
  261.                  * TCL_QUEUE_MARK. */
  262. {
  263.     if (!initialized) {
  264.     InitNotifier();
  265.     }
  266.  
  267.     if (position == TCL_QUEUE_TAIL) {
  268.     /*
  269.      * Append the event on the end of the queue.
  270.      */
  271.  
  272.     evPtr->nextPtr = NULL;
  273.     if (notifier.firstEventPtr == NULL) {
  274.         notifier.firstEventPtr = evPtr;
  275.     } else {
  276.         notifier.lastEventPtr->nextPtr = evPtr;
  277.     }
  278.     notifier.lastEventPtr = evPtr;
  279.     } else if (position == TCL_QUEUE_HEAD) {
  280.     /*
  281.      * Push the event on the head of the queue.
  282.      */
  283.  
  284.     evPtr->nextPtr = notifier.firstEventPtr;
  285.     if (notifier.firstEventPtr == NULL) {
  286.         notifier.lastEventPtr = evPtr;
  287.     }        
  288.     notifier.firstEventPtr = evPtr;
  289.     } else if (position == TCL_QUEUE_MARK) {
  290.     /*
  291.      * Insert the event after the current marker event and advance
  292.      * the marker to the new event.
  293.      */
  294.  
  295.     if (notifier.markerEventPtr == NULL) {
  296.         evPtr->nextPtr = notifier.firstEventPtr;
  297.         notifier.firstEventPtr = evPtr;
  298.     } else {
  299.         evPtr->nextPtr = notifier.markerEventPtr->nextPtr;
  300.         notifier.markerEventPtr->nextPtr = evPtr;
  301.     }
  302.     notifier.markerEventPtr = evPtr;
  303.     if (evPtr->nextPtr == NULL) {
  304.         notifier.lastEventPtr = evPtr;
  305.     }
  306.     }
  307. }
  308.  
  309. /*
  310.  *----------------------------------------------------------------------
  311.  *
  312.  * Tcl_DeleteEvents --
  313.  *
  314.  *    Calls a procedure for each event in the queue and deletes those
  315.  *    for which the procedure returns 1. Events for which the
  316.  *    procedure returns 0 are left in the queue.
  317.  *
  318.  * Results:
  319.  *    None.
  320.  *
  321.  * Side effects:
  322.  *    Potentially removes one or more events from the event queue.
  323.  *
  324.  *----------------------------------------------------------------------
  325.  */
  326.  
  327. void
  328. Tcl_DeleteEvents(proc, clientData)
  329.     Tcl_EventDeleteProc *proc;        /* The procedure to call. */
  330.     ClientData clientData;            /* type-specific data. */
  331. {
  332.     Tcl_Event *evPtr, *prevPtr, *hold;
  333.  
  334.     if (!initialized) {
  335.     InitNotifier();
  336.     }
  337.  
  338.     for (prevPtr = (Tcl_Event *) NULL, evPtr = notifier.firstEventPtr;
  339.              evPtr != (Tcl_Event *) NULL;
  340.              ) {
  341.         if ((*proc) (evPtr, clientData) == 1) {
  342.             if (notifier.firstEventPtr == evPtr) {
  343.                 notifier.firstEventPtr = evPtr->nextPtr;
  344.                 if (evPtr->nextPtr == (Tcl_Event *) NULL) {
  345.                     notifier.lastEventPtr = (Tcl_Event *) NULL;
  346.                 }
  347.             } else {
  348.                 prevPtr->nextPtr = evPtr->nextPtr;
  349.             }
  350.             hold = evPtr;
  351.             evPtr = evPtr->nextPtr;
  352.             ckfree((char *) hold);
  353.         } else {
  354.             prevPtr = evPtr;
  355.             evPtr = evPtr->nextPtr;
  356.         }
  357.     }
  358. }
  359.  
  360. /*
  361.  *----------------------------------------------------------------------
  362.  *
  363.  * Tcl_ServiceEvent --
  364.  *
  365.  *    Process one event from the event queue, or invoke an
  366.  *    asynchronous event handler.
  367.  *
  368.  * Results:
  369.  *    The return value is 1 if the procedure actually found an event
  370.  *    to process.  If no processing occurred, then 0 is returned.
  371.  *
  372.  * Side effects:
  373.  *    Invokes all of the event handlers for the highest priority
  374.  *    event in the event queue.  May collapse some events into a
  375.  *    single event or discard stale events.
  376.  *
  377.  *----------------------------------------------------------------------
  378.  */
  379.  
  380. int
  381. Tcl_ServiceEvent(flags)
  382.     int flags;            /* Indicates what events should be processed.
  383.                  * May be any combination of TCL_WINDOW_EVENTS
  384.                  * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
  385.                  * flags defined elsewhere.  Events not
  386.                  * matching this will be skipped for processing
  387.                  * later. */
  388. {
  389.     Tcl_Event *evPtr, *prevPtr;
  390.     Tcl_EventProc *proc;
  391.  
  392.     if (!initialized) {
  393.     InitNotifier();
  394.     }
  395.  
  396.     /*
  397.      * Asynchronous event handlers are considered to be the highest
  398.      * priority events, and so must be invoked before we process events
  399.      * on the event queue.
  400.      */
  401.     
  402.     if (Tcl_AsyncReady()) {
  403.     (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
  404.     return 1;
  405.     }
  406.  
  407.     /*
  408.      * No event flags is equivalent to TCL_ALL_EVENTS.
  409.      */
  410.     
  411.     if ((flags & TCL_ALL_EVENTS) == 0) {
  412.     flags |= TCL_ALL_EVENTS;
  413.     }
  414.  
  415.     /*
  416.      * Loop through all the events in the queue until we find one
  417.      * that can actually be handled.
  418.      */
  419.  
  420.     for (evPtr = notifier.firstEventPtr; evPtr != NULL;
  421.      evPtr = evPtr->nextPtr) {
  422.     /*
  423.      * Call the handler for the event.  If it actually handles the
  424.      * event then free the storage for the event.  There are two
  425.      * tricky things here, but stemming from the fact that the event
  426.      * code may be re-entered while servicing the event:
  427.      *
  428.      * 1. Set the "proc" field to NULL.  This is a signal to ourselves
  429.      *    that we shouldn't reexecute the handler if the event loop
  430.      *    is re-entered.
  431.      * 2. When freeing the event, must search the queue again from the
  432.      *    front to find it.  This is because the event queue could
  433.      *    change almost arbitrarily while handling the event, so we
  434.      *    can't depend on pointers found now still being valid when
  435.      *    the handler returns.
  436.      */
  437.  
  438.     proc = evPtr->proc;
  439.     evPtr->proc = NULL;
  440.     if ((proc != NULL) && (*proc)(evPtr, flags)) {
  441.         if (notifier.firstEventPtr == evPtr) {
  442.         notifier.firstEventPtr = evPtr->nextPtr;
  443.         if (evPtr->nextPtr == NULL) {
  444.             notifier.lastEventPtr = NULL;
  445.         }
  446.         if (notifier.markerEventPtr == evPtr) {
  447.             notifier.markerEventPtr = NULL;
  448.         }
  449.         } else {
  450.         for (prevPtr = notifier.firstEventPtr;
  451.              prevPtr->nextPtr != evPtr; prevPtr = prevPtr->nextPtr) {
  452.             /* Empty loop body. */
  453.         }
  454.         prevPtr->nextPtr = evPtr->nextPtr;
  455.         if (evPtr->nextPtr == NULL) {
  456.             notifier.lastEventPtr = prevPtr;
  457.         }
  458.         if (notifier.markerEventPtr == evPtr) {
  459.             notifier.markerEventPtr = prevPtr;
  460.         }
  461.         }
  462.         ckfree((char *) evPtr);
  463.         return 1;
  464.     } else {
  465.         /*
  466.          * The event wasn't actually handled, so we have to restore
  467.          * the proc field to allow the event to be attempted again.
  468.          */
  469.  
  470.         evPtr->proc = proc;
  471.     }
  472.  
  473.     /*
  474.      * The handler for this event asked to defer it.  Just go on to
  475.      * the next event.
  476.      */
  477.  
  478.     continue;
  479.     }
  480.     return 0;
  481. }
  482.  
  483. /*
  484.  *----------------------------------------------------------------------
  485.  *
  486.  * Tcl_GetServiceMode --
  487.  *
  488.  *    This routine returns the current service mode of the notifier.
  489.  *
  490.  * Results:
  491.  *    Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
  492.  *
  493.  * Side effects:
  494.  *    None.
  495.  *
  496.  *----------------------------------------------------------------------
  497.  */
  498.  
  499. int
  500. Tcl_GetServiceMode()
  501. {
  502.     if (!initialized) {
  503.     InitNotifier();
  504.     }
  505.  
  506.     return notifier.serviceMode;
  507. }
  508.  
  509. /*
  510.  *----------------------------------------------------------------------
  511.  *
  512.  * Tcl_SetServiceMode --
  513.  *
  514.  *    This routine sets the current service mode of the notifier.
  515.  *
  516.  * Results:
  517.  *    Returns the previous service mode.
  518.  *
  519.  * Side effects:
  520.  *    None.
  521.  *
  522.  *----------------------------------------------------------------------
  523.  */
  524.  
  525. int
  526. Tcl_SetServiceMode(mode)
  527.     int mode;            /* New service mode: TCL_SERVICE_ALL or
  528.                  * TCL_SERVICE_NONE */
  529. {
  530.     int oldMode;
  531.  
  532.     if (!initialized) {
  533.     InitNotifier();
  534.     }
  535.  
  536.     oldMode = notifier.serviceMode;
  537.     notifier.serviceMode = mode;
  538.     return oldMode;
  539. }
  540.  
  541. /*
  542.  *----------------------------------------------------------------------
  543.  *
  544.  * Tcl_SetMaxBlockTime --
  545.  *
  546.  *    This procedure is invoked by event sources to tell the notifier
  547.  *    how long it may block the next time it blocks.  The timePtr
  548.  *    argument gives a maximum time;  the actual time may be less if
  549.  *    some other event source requested a smaller time.
  550.  *
  551.  * Results:
  552.  *    None.
  553.  *
  554.  * Side effects:
  555.  *    May reduce the length of the next sleep in the notifier.
  556.  *
  557.  *----------------------------------------------------------------------
  558.  */
  559.  
  560. void
  561. Tcl_SetMaxBlockTime(timePtr)
  562.     Tcl_Time *timePtr;        /* Specifies a maximum elapsed time for
  563.                  * the next blocking operation in the
  564.                  * event notifier. */
  565. {
  566.     if (!initialized) {
  567.     InitNotifier();
  568.     }
  569.  
  570.     if (!notifier.blockTimeSet || (timePtr->sec < notifier.blockTime.sec)
  571.         || ((timePtr->sec == notifier.blockTime.sec)
  572.         && (timePtr->usec < notifier.blockTime.usec))) {
  573.     notifier.blockTime = *timePtr;
  574.     notifier.blockTimeSet = 1;
  575.     }
  576.  
  577.     /*
  578.      * If we are called outside an event source traversal, set the
  579.      * timeout immediately.
  580.      */
  581.  
  582.     if (!notifier.inTraversal) {
  583.     if (notifier.blockTimeSet) {
  584.         Tcl_SetTimer(¬ifier.blockTime);
  585.     } else {
  586.         Tcl_SetTimer(NULL);
  587.     }
  588.     }
  589. }
  590.  
  591. /*
  592.  *----------------------------------------------------------------------
  593.  *
  594.  * Tcl_DoOneEvent --
  595.  *
  596.  *    Process a single event of some sort.  If there's no work to
  597.  *    do, wait for an event to occur, then process it.
  598.  *
  599.  * Results:
  600.  *    The return value is 1 if the procedure actually found an event
  601.  *    to process.  If no processing occurred, then 0 is returned (this
  602.  *    can happen if the TCL_DONT_WAIT flag is set or if there are no
  603.  *    event handlers to wait for in the set specified by flags).
  604.  *
  605.  * Side effects:
  606.  *    May delay execution of process while waiting for an event,
  607.  *    unless TCL_DONT_WAIT is set in the flags argument.  Event
  608.  *    sources are invoked to check for and queue events.  Event
  609.  *    handlers may produce arbitrary side effects.
  610.  *
  611.  *----------------------------------------------------------------------
  612.  */
  613.  
  614. int
  615. Tcl_DoOneEvent(flags)
  616.     int flags;            /* Miscellaneous flag values:  may be any
  617.                  * combination of TCL_DONT_WAIT,
  618.                  * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
  619.                  * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
  620.                  * others defined by event sources. */
  621. {
  622.     int result = 0, oldMode;
  623.     EventSource *sourcePtr;
  624.     Tcl_Time *timePtr;
  625.  
  626.     if (!initialized) {
  627.     InitNotifier();
  628.     }
  629.  
  630.     /*
  631.      * The first thing we do is to service any asynchronous event
  632.      * handlers.
  633.      */
  634.     
  635.     if (Tcl_AsyncReady()) {
  636.     (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
  637.     return 1;
  638.     }
  639.  
  640.     /*
  641.      * No event flags is equivalent to TCL_ALL_EVENTS.
  642.      */
  643.     
  644.     if ((flags & TCL_ALL_EVENTS) == 0) {
  645.     flags |= TCL_ALL_EVENTS;
  646.     }
  647.  
  648.     /*
  649.      * Set the service mode to none so notifier event routines won't
  650.      * try to service events recursively.
  651.      */
  652.  
  653.     oldMode = notifier.serviceMode;
  654.     notifier.serviceMode = TCL_SERVICE_NONE;
  655.  
  656.     /*
  657.      * The core of this procedure is an infinite loop, even though
  658.      * we only service one event.  The reason for this is that we
  659.      * may be processing events that don't do anything inside of Tcl.
  660.      */
  661.  
  662.     while (1) {
  663.  
  664.     /*
  665.      * If idle events are the only things to service, skip the
  666.      * main part of the loop and go directly to handle idle
  667.      * events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
  668.      */
  669.  
  670.     if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
  671.         flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
  672.         goto idleEvents;
  673.     }
  674.  
  675.     /*
  676.      * Ask Tcl to service a queued event, if there are any.
  677.      */
  678.  
  679.     if (Tcl_ServiceEvent(flags)) {
  680.         result = 1;        
  681.         break;
  682.     }
  683.  
  684.     /*
  685.      * If TCL_DONT_WAIT is set, be sure to poll rather than
  686.      * blocking, otherwise reset the block time to infinity.
  687.      */
  688.  
  689.     if (flags & TCL_DONT_WAIT) {
  690.         notifier.blockTime.sec = 0;
  691.         notifier.blockTime.usec = 0;
  692.         notifier.blockTimeSet = 1;
  693.     } else {
  694.         notifier.blockTimeSet = 0;
  695.     }
  696.  
  697.     /*
  698.      * Set up all the event sources for new events.  This will
  699.      * cause the block time to be updated if necessary.
  700.      */
  701.  
  702.     notifier.inTraversal = 1;
  703.     for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
  704.          sourcePtr = sourcePtr->nextPtr) {
  705.         if (sourcePtr->setupProc) {
  706.         (sourcePtr->setupProc)(sourcePtr->clientData, flags);
  707.         }
  708.     }
  709.     notifier.inTraversal = 0;
  710.  
  711.     if ((flags & TCL_DONT_WAIT) || notifier.blockTimeSet) {
  712.         timePtr = ¬ifier.blockTime;
  713.     } else {
  714.         timePtr = NULL;
  715.     }
  716.  
  717.     /*
  718.      * Wait for a new event or a timeout.  If Tcl_WaitForEvent
  719.      * returns -1, we should abort Tcl_DoOneEvent.
  720.      */
  721.  
  722.     result = Tcl_WaitForEvent(timePtr);
  723.     if (result < 0) {
  724.         result = 0;
  725.         break;
  726.     }
  727.  
  728.     /*
  729.      * Check all the event sources for new events.
  730.      */
  731.  
  732.     for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
  733.          sourcePtr = sourcePtr->nextPtr) {
  734.         if (sourcePtr->checkProc) {
  735.         (sourcePtr->checkProc)(sourcePtr->clientData, flags);
  736.         }
  737.     }
  738.  
  739.     /*
  740.      * Check for events queued by the notifier or event sources.
  741.      */
  742.  
  743.     if (Tcl_ServiceEvent(flags)) {
  744.         result = 1;
  745.         break;
  746.     }
  747.  
  748.     /*
  749.      * We've tried everything at this point, but nobody we know
  750.      * about had anything to do.  Check for idle events.  If none,
  751.      * either quit or go back to the top and try again.
  752.      */
  753.  
  754.     idleEvents:
  755.     if (flags & TCL_IDLE_EVENTS) {
  756.         if (TclServiceIdle()) {
  757.         result = 1;
  758.         break;
  759.         }
  760.     }
  761.     if (flags & TCL_DONT_WAIT) {
  762.         break;
  763.     }
  764.     }
  765.  
  766.     notifier.serviceMode = oldMode;
  767.     return result;
  768. }
  769.  
  770. /*
  771.  *----------------------------------------------------------------------
  772.  *
  773.  * Tcl_ServiceAll --
  774.  *
  775.  *    This routine checks all of the event sources, processes
  776.  *    events that are on the Tcl event queue, and then calls the
  777.  *    any idle handlers.  Platform specific notifier callbacks that
  778.  *    generate events should call this routine before returning to
  779.  *    the system in order to ensure that Tcl gets a chance to
  780.  *    process the new events.
  781.  *
  782.  * Results:
  783.  *    Returns 1 if an event or idle handler was invoked, else 0.
  784.  *
  785.  * Side effects:
  786.  *    Anything that an event or idle handler may do.
  787.  *
  788.  *----------------------------------------------------------------------
  789.  */
  790.  
  791. int
  792. Tcl_ServiceAll()
  793. {
  794.     int result = 0;
  795.     EventSource *sourcePtr;
  796.  
  797.     if (!initialized) {
  798.     InitNotifier();
  799.     }
  800.  
  801.     if (notifier.serviceMode == TCL_SERVICE_NONE) {
  802.     return result;
  803.     }
  804.  
  805.     /*
  806.      * We need to turn off event servicing like we to in Tcl_DoOneEvent,
  807.      * to avoid recursive calls.
  808.      */
  809.     
  810.     notifier.serviceMode = TCL_SERVICE_NONE;
  811.  
  812.     /*
  813.      * Check async handlers first.
  814.      */
  815.  
  816.     if (Tcl_AsyncReady()) {
  817.     (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
  818.     }
  819.  
  820.     /*
  821.      * Make a single pass through all event sources, queued events,
  822.      * and idle handlers.  Note that we wait to update the notifier
  823.      * timer until the end so we can avoid multiple changes.
  824.      */
  825.  
  826.     notifier.inTraversal = 1;
  827.     notifier.blockTimeSet = 0;
  828.  
  829.     for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
  830.      sourcePtr = sourcePtr->nextPtr) {
  831.     if (sourcePtr->setupProc) {
  832.         (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
  833.     }
  834.     }
  835.     for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
  836.      sourcePtr = sourcePtr->nextPtr) {
  837.     if (sourcePtr->checkProc) {
  838.         (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
  839.     }
  840.     }
  841.  
  842.     while (Tcl_ServiceEvent(0)) {
  843.     result = 1;
  844.     }
  845.     if (TclServiceIdle()) {
  846.     result = 1;
  847.     }
  848.  
  849.     if (!notifier.blockTimeSet) {
  850.     Tcl_SetTimer(NULL);
  851.     } else {
  852.     Tcl_SetTimer(¬ifier.blockTime);
  853.     }
  854.     notifier.inTraversal = 0;
  855.     notifier.serviceMode = TCL_SERVICE_ALL;
  856.     return result;
  857. }
  858.